package hh.util.coll;

import hh.util.Asserts;
import hh.util.CommonUtil;
import hh.util.arr.ArrUtil;
import hh.util.Fun;

import java.io.Serializable;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CollUtil implements Serializable {
    private CollUtil() {
    }


    public static <T> List<T> subList(List<T> list, int size, int page) {
        int from = (page - 1) * size;
        if (from >= list.size()) {
            from = list.size() - 1;
        }
        int to = from + size;
        if (to >= list.size()) {
            to = list.size();
        }
        return list.subList(from, to);
    }

    public static void main(String[] args) {
        List<Integer> integers = newArrayList(1, 2, 3, 4, 5);
        ListIterator<Integer> it = integers.listIterator();
        while (it.hasNext()) {
            Integer next = it.next();
            if (next == 2) {
                it.remove();
                it.add(123);
            }
        }

        System.out.println(integers);


        List<Integer> list = newArrayList(null);
        Integer min = min(list, e -> e);
        System.out.println(min);
    }

    public static <T, R extends Number> T min(List<T> list, Function<T, R> fun) {
        if (isEmpty(list) || fun == null) return null;
        double minNum = 0;
        T min = null;
        for (T t : list) {
            R apply = fun.apply(t);
            if (apply == null) continue;
            if (min == null) {
                min = t;
                minNum = apply.doubleValue();
                continue;
            }
            if (apply.doubleValue() < minNum) {
                minNum = apply.doubleValue();
                min = t;
            }
        }
        return min;
    }

    public static <T, R extends Number> List<T> min(List<T> list, Function<T, R> fun, int nums) {
        if (isEmpty(list) || nums >= list.size() || fun == null) return list;
        List<T> data = new ArrayList<>(nums);
        T min = null;
        R minNum = null;

        for (T t : list) {
            R apply = fun.apply(t);
            if (apply == null) continue;

            if (data.size() < nums) {
                data.add(t);
                data.sort((e1, e2) -> (int) (fun.apply(e1).doubleValue() - fun.apply(e2).doubleValue()));
            } else {
                for (int i = 0; i < nums; i++) {
                    if (apply.doubleValue() < fun.apply(data.get(i)).doubleValue()) {

                    }
                }
            }

        }


        for (int i = 0; i < nums; i++) {
            for (int j = 0; j < list.size() - i - 1; j++) {
                R apply1 = fun.apply(list.get(j));
                if (apply1 == null) continue;
                if (min == null) {
                    min = list.get(j);
                    minNum = apply1;
                    continue;
                }

                if (apply1.doubleValue() < minNum.doubleValue()) {
                    minNum = apply1;
                    min = list.get(j);
                }

            }
            if (min != null) data.add(min);
            min = null;
        }
        return data;

    }

    public static <T> T checkRepeat(T[] arr) {
        return checkRepeat(arr, e -> e);
    }


    public static <T, R> R checkRepeat(T[] arr, Function<T, R> column) {
        if (isEmpty(arr)) return null;
        Set<R> set = new HashSet<>(arr.length * 2);
        for (T t : arr) {
            R apply = column.apply(t);
            if (apply == null) continue;
            if (set.contains(apply)) {
                return apply;
            } else {
                set.add(apply);
            }
        }
        return null;
    }

    public static <T> T checkRepeat(Collection<T> collection) {
        return checkRepeat(collection, e -> e);
    }

    public static <T, R> R checkRepeat(Collection<T> collection, Function<T, R> column) {
        if (isEmpty(collection)) return null;
        Set<R> set = new HashSet<>(collection.size() * 2);
        for (T t : collection) {
            R apply = column.apply(t);
            if (apply == null) continue;
            if (set.contains(apply)) {
                return apply;
            } else {
                set.add(apply);
            }
        }
        return null;
    }


    public static <T> boolean isEmpty(T[] arr) {
        return arr == null || arr.length == 0;
    }


    public static boolean isEmpty(Map<?, ?> m) {
        return m == null || m.isEmpty();
    }

    public static boolean isEmpty(Collection<?> m) {
        return m == null || m.isEmpty();
    }

    public static boolean isNotEmpty(Map<?, ?> m) {
        return !isEmpty(m);
    }

    public static boolean isNotEmpty(Collection<?> m) {
        return !isEmpty(m);
    }


    public static <T> List<List<T>> subList(List<T> list, int size) {
        if (isEmpty(list) || size <= 0) {
            return new ArrayList<>(0);
        }
        List<List<T>> rs = new ArrayList<>();
        int totalPage = (list.size() + size - 1) / size;
        for (int i = 0; i < totalPage - 1; i++) {
            int from = i * size;
            rs.add(list.subList(from, from + size));
        }
        rs.add(list.subList(size * (totalPage - 1), list.size()));
        return rs;
    }


    public static <T> T syncPut(Map<Object, T> source, Object key, Fun.F01<T> fun01) {
        T t = source.get(key);
        if (t == null) {
            synchronized (source) {
                if ((t = source.get(key)) == null) {
                    source.put(key, t = fun01.apply());
                }
            }
        }
        return t;

    }
//	-------------------- 以下方法快速创建一个集合, 省去了new 操作 以及add put操作 -------------------------------------------

    public static <T> T[] newArray(T... values) {
        return values;
    }

    public static <T> List<T> newArrayList(T... values) {
        return (List<T>) wrapColl(new ArrayList<>(), values);
    }

    public static <T> Set<T> newHashSet(T... values) {
        return (Set<T>) wrapColl(new HashSet<>(), values);
    }

    private static <T> Collection<T> wrapColl(Collection<T> coll, T... values) {
        if (CommonUtil.isEmpty(values)) {
            return coll;
        }
        for (T value : values) {
            coll.add(value);
        }
        return coll;
    }

    public static <K, V> Map<K, V> newHashMap(K key, V value) {
        return newHashMap(key, value, 16);
    }

    public static Map newHashMapKvs(Object... kvs) {
        HashMap<Object, Object> map = new HashMap<>();
        if (kvs == null) return map;
        Asserts.True(kvs.length % 2 != 0, "参数必须是偶数");
        for (int i = 0; i < kvs.length; i++) {
            map.put(kvs[i], kvs[++i]);
        }
        return map;
    }

    public static Map newTreeMapKvs(Object... kvs) {
        TreeMap<Object, Object> map = new TreeMap<>();
        if (kvs == null) return map;
        Asserts.True(kvs.length % 2 != 0, "参数必须是偶数");
        for (int i = 0; i < kvs.length; i++) {
            map.put(kvs[i], kvs[++i]);
        }
        return map;
    }

    public static Map newHashMapKeys(Object... kvs) {
        HashMap<Object, Object> map = new HashMap<>();
        if (kvs == null) return map;
        for (int i = 0; i < kvs.length; i++) {
            map.put(kvs[i], null);
        }
        return map;
    }

    public static <K, V> Map<K, V> newHashMap(K key, V value, int capacity) {
        Map<K, V> map = new HashMap<>(capacity);
        map.put(key, value);
        return map;
    }


    /**
     * e.g:
     * <p>
     * List<User> users;
     * mapCollect(users,user->user.getId()) return List<Long> ids
     * </p>
     *
     * @param filterNull 是否需要过滤null 如果是true，list元素为空，以及经过apply后返回空都会过滤
     */
    private static <T, R> List<R> collect(Collection<T> data, Function<? super T, ? extends R> mapper, boolean filterNull) {
        if (isEmpty(data) || mapper == null) {
            return new ArrayList<>(0);
        }
        Stream<? extends R> stream = data.stream().map(mapper);
        if (filterNull) {
            stream = stream.filter(Objects::nonNull);
        }
        return stream.collect(Collectors.toList());
    }

    /**
     * 替代 list.stream().map(e->e.getXXX()).collect(Collectors.toList()); <br>
     * <p>
     */
    public static <T, R> List<R> collect(Collection<T> data, Function<? super T, ? extends R> mapFun) {
        return collect(data, mapFun, true);
    }


    /**
     * 不可变集合
     */
    public static <T> List<T> immutableList(T... elements) {
        if (ArrUtil.isEmpty(elements)) {
            return Collections.unmodifiableList(new ArrayList<>(0));
        }
        return Collections.unmodifiableList(Arrays.asList(elements));
    }

    public static <T> List<T> filterContain(List<T> source, Collection<T> dest) {
        if (isEmpty(source)) return new ArrayList<>(0);
        if (isEmpty(dest)) return source;

        Map<T, T> map = dest.stream().collect(Collectors.toMap(e -> e, e -> e, (e1, e2) -> e1));
        return source.stream().filter(e -> map.containsKey(e)).collect(Collectors.toList());
    }

    public static <T> List<T> filterNoContain(List<T> source, Collection<T> dest) {
        if (isEmpty(source)) return new ArrayList<>(0);
        if (isEmpty(dest)) return source;

        Map<T, T> map = dest.stream().collect(Collectors.toMap(e -> e, e -> e, (e1, e2) -> e1));
        return source.stream().filter(e -> !map.containsKey(e)).collect(Collectors.toList());
    }


    public static <T> List<T> merge(Collection<T>... collections) {
        if (collections == null) return new ArrayList<>(0);
        List<T> list = new ArrayList<>();
        for (Collection<T> c : collections) {
            if (isNotEmpty(c)) list.addAll(list);
        }
        return list;

    }


}
